package routers

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"server/global"
	"server/internal/model"
	"server/internal/service"
	"server/pkg/app"
	"server/pkg/errcode"

	"github.com/gin-gonic/gin"
)

type Account struct{}

func NewAccount() *Account {
	return &Account{}
}

// @Summary 注册
// @Produce json
// @Param username body string true "用户名"
// @Param password body string true "密码" minlength(6) maxlength(16)
// @Success 200 {string} string "成功"
// @Failure 400 {object} errcode.Error "请求失败"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /user/register [post]
func (a *Account) Register(c *gin.Context) {
	param := &struct {
		Username string `form:"username" binding:"required,min=3,max=20"`
		Password string `form:"password" binding:"required,min=3,max=16"`
	}{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, param)
	if !valid {
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	svc := service.New(c.Request.Context())
	success, err := svc.Register(param.Username, param.Password)
	if err != nil {
		global.Logger.Errorf("svc.Register err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	if !success {
		response.ToErrorResponse(errcode.ErrorUserExist)
		return
	}

	response.ToSuccessResponse(nil)
}

// @Summary 登录
// @Produce json
// @Param username body string true "用户名"
// @Param password body string true "密码" minlength(6) maxlength(16)
// @Success 200 {string} string "成功"
// @Failure 400 {object} errcode.Error "请求失败"
// @Failure 500 {object} errcode.Error "内部错误"
// @Router /user/login [post]
func (a *Account) Login(c *gin.Context) {
	param := &struct {
		Username string `form:"username" binding:"required,min=3,max=20"`
		Password string `form:"password" binding:"required,min=3,max=16"`
	}{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, param)
	if !valid {
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	svc := service.New(c.Request.Context())
	rank, err := svc.Login(param.Username, param.Password)
	if err != nil {
		global.Logger.Errorf("svc.Login err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	if rank == model.NoRank {
		response.ToErrorResponse(errcode.ErrorLoginFail)
		return
	}

	token, err := app.GenerateToken(param.Username, param.Password, rank)
	if err != nil {
		global.Logger.Errorf("app.GenerateToken err: %v", err)
		response.ToErrorResponse(errcode.UnauthorizedTokenGenerate)
		return
	}

	response.ToSuccessResponse(gin.H{
		"rank":  rank,
		"token": token,
	})
}

func (a *Account) GetAllUsers(c *gin.Context) {
	response := app.NewResponse(c)
	svc := service.New(c.Request.Context())
	users, err := svc.GetAllUsers()
	if err != nil {
		global.Logger.Errorf("svc.GetAllUsers err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	response.ToSuccessResponse(gin.H{
		"users": users,
	})
}

func (a *Account) GetAllTeachers(c *gin.Context) {
	response := app.NewResponse(c)
	svc := service.New(c.Request.Context())
	teachers, err := svc.GetAllTeachers()
	if err != nil {
		global.Logger.Errorf("svc.GetAllTeachers err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	response.ToSuccessResponse(gin.H{
		"users": teachers,
	})
}

func (a *Account) GetAllStudents(c *gin.Context) {
	response := app.NewResponse(c)
	svc := service.New(c.Request.Context())
	students, err := svc.GetAllStudents()
	if err != nil {
		global.Logger.Errorf("svc.GetAllStudents err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	response.ToSuccessResponse(gin.H{
		"users": students,
	})
}

func (a *Account) RemoveUser(c *gin.Context) {
	param := &struct {
		ID int `form:"id" binding:"required"`
	}{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, param)
	if !valid {
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	svc := service.New(c.Request.Context())
	err := svc.RemoveUser(param.ID)
	if err != nil {
		global.Logger.Errorf("svc.RemoveUser err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	response.ToSuccessResponse(nil)
}

func (a *Account) IncreaseRank(c *gin.Context) {
	param := &struct {
		ID int `form:"id" binding:"required"`
	}{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, param)
	if !valid {
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	svc := service.New(c.Request.Context())
	err := svc.IncreaseRank(param.ID)
	if err != nil {
		global.Logger.Errorf("svc.IncreaseRank err: %v", err)
		response.ToErrorResponse(errcode.ErrorGetAccountFail)
		return
	}

	response.ToSuccessResponse(nil)
}

func (a *Account) GetTransaction(c *gin.Context) {
	param := &struct {
		TxId string `form:"txId" binding:"required"`
	}{}
	response := app.NewResponse(c)
	valid, errs := app.BindAndValid(c, param)
	if !valid {
		global.Logger.Errorf("app.BindAndValid errs: %v", errs)
		errRsp := errcode.InvalidParams.WithDetails(errs.Errors()...)
		response.ToErrorResponse(errRsp)
		return
	}

	info := make(map[string]interface{})
	info["txId"] = param.TxId

	body, err := json.Marshal(info)
	if err != nil {
		response.ToSuccessResponse("marshal err")
		return
	}

	reader := bytes.NewReader(body)

	resp, err := http.Post("http://localhost:11080/getTransaction", "application/json;charset=utf-8", reader)

	if err != nil {
		response.ToSuccessResponse("http post error")
		return
	}

	res, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		response.ToSuccessResponse("read all error")
		return
	}

	response.ToSuccessResponse(string(res))
}
